using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EntitiesAndMappings.Entities;
using NHibernate;
using NHibernate.Transform;

namespace ProyectoActivos.Daos
{
    public class ConsultasDAO : BaseDAO<Object>
    {
        public IList<ConsultaInventarioDTO> ObtenerConsultaInventario(DateTime fecha)
        {
            IList<ConsultaInventarioDTO> lista;
            using (var session = CreateSessionFactory().OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    var query=session.CreateSQLQuery(
                    @"  select x.NombreSubFamilia as NombreSubFamilia,
	                           x.NombreFamilia as NombreFamilia,
	                           x.NombreMarca as NombreMarca,
	                           x.Modelo as Modelo,
	                           x.Serie as Serie,
	                           x.CodigoArticulo as CodigoArticulo,
	                           x.DescripcionArticulo as DescripcionArticulo,
	                           abs(sum(x.cantidad)) as Cantidad,
	                           x.NombreAlmacen as NombreAlmacen,
	                           x.NombreProyecto as NombreProyecto,
	                           x.NombreLocal as NombreLote,
	                           x.NombreLugar as NombreLugar,
	                           x.Ubicacion as Ubicacion,
	                           x.NombreCondicionEquipo as NombreCondicionEquipo
                        from 
                        (
	                        select	sf.Descripcion as NombreSubFamilia,
			                        f.Descripcion as NombreFamilia,
			                        m.Descripcion as NombreMarca,
			                        ar.Modelo as Modelo,
			                        ar.Serie as Serie,
			                        ar.Codigo as CodigoArticulo,
			                        ar.Descripcion as DescripcionArticulo,
			                        sum(di.cantidad) as Cantidad,
			                        a.Nombre as NombreAlmacen,
			                        p.Descripcion as NombreProyecto,
			                        lo.Descripcion as NombreLocal,
			                        lu.Descripcion as NombreLugar,
			                        i.ubicacion as Ubicacion,
			                        ce.Descripcion as NombreCondicionEquipo
	                        from	DetalleIngreso di 
			                        inner join Ingreso i on di.ingreso_id = i.id
			                        inner join CondicionEquipo ce on di.CondicionEquipo_id = ce.Id
			                        left join Almacen a on i.almacen_id = a.id
			                        left join proyecto p on i.proyecto_id = p.id
			                        left join lote lo on i.lote_id = lo.id
			                        left join lugar lu on i.lugar_id = lu.id
			                        inner join articulo ar on di.articulo_id = ar.Id
			                        inner join Marca m on ar.Marca_id = m.Id
			                        inner join SubFamilia sf on ar.SubFamilia_id = sf.Id
			                        inner join Familia f on sf.Familia_id = f.Id
	                        where i.fecha <= ?  and ar.Estado = 'A'
	                        group by	sf.Descripcion,
				                        f.Descripcion,
				                        ar.Codigo,
				                        ar.Descripcion,
				                        a.Nombre,
				                        p.Descripcion,
				                        lo.Descripcion,
				                        lu.Descripcion,
				                        i.ubicacion,
				                        m.Descripcion,
				                        ar.Serie,
				                        ar.Modelo,
				                        ce.Descripcion
	                        union
	                        select	sf.Descripcion as NombreSubFamilia,
			                        f.Descripcion as NombreFamilia,
			                        m.Descripcion as NombreMarca,
			                        ar.Modelo as Modelo,
			                        ar.Serie as Serie,
			                        ar.Codigo as CodigoArticulo,
			                        ar.Descripcion as DescripcionArticulo,
			                        -1*sum(ds.cantidad) as Cantidad,
			                        a.Nombre as NombreAlmacen,
			                        p.Descripcion as NombreProyecto,
			                        lo.Descripcion as NombreLocal,
			                        lu.Descripcion as NombreLugar,
			                        s.ubicacion as Ubicacion,
			                        ce.Descripcion as NombreCondicionEquipo
	                        from	DetalleSalida ds 
			                        inner join salida s on ds.salida_id = s.id
			                        inner join CondicionEquipo ce on ds.CondicionEquipo_id = ce.Id
			                        left join Almacen a on s.almacen_id = a.id
			                        left join proyecto p on s.proyecto_id = p.id
			                        left join lote lo on s.lote_id = lo.id
			                        left join lugar lu on s.lugar_id = lu.id
			                        inner join articulo ar on ds.articulo_id = ar.Id
			                        inner join Marca m on ar.Marca_id = m.Id
			                        inner join SubFamilia sf on ar.SubFamilia_id = sf.Id
			                        inner join Familia f on sf.Familia_id = f.Id
	                        where s.fecha <= ?  and ar.Estado = 'A'
	                        group by	sf.Descripcion,
				                        f.Descripcion,
				                        ar.Codigo,
				                        ar.Descripcion,
				                        a.Nombre,
				                        p.Descripcion,
				                        lo.Descripcion,
				                        lu.Descripcion,
				                        s.ubicacion,
				                        m.Descripcion,
				                        ar.Serie,
				                        ar.Modelo,
				                        ce.Descripcion
                        ) x
                        group by 
	                        x.NombreSubFamilia,
	                        x.NombreFamilia,
	                        x.NombreMarca,
	                        x.Modelo,
	                        x.Serie,
	                        x.CodigoArticulo,
	                        x.DescripcionArticulo,
	                        x.NombreAlmacen,
	                        x.NombreProyecto,
	                        x.NombreLocal,
	                        x.NombreLugar,
	                        x.Ubicacion,
	                        x.NombreCondicionEquipo");
                    query.SetDateTime(0,fecha);
                    query.SetDateTime(1, fecha);
                    query.SetResultTransformer(Transformers.AliasToBean(typeof (ConsultaInventarioDTO)));
                    lista = query.List<ConsultaInventarioDTO>();
                    transaction.Commit();
                }
            }
            return lista;
        }

        public IList<ConsultaMantenimientoDTO> ObtenerConsultaMantenimiento(Articulo articulo, DateTime fechaInicio, DateTime fechaFin)
        {
            IList<ConsultaMantenimientoDTO> lista;
            using (var session = CreateSessionFactory().OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    var query = session.CreateSQLQuery(
                    @"select	i.Fecha as Fecha,
		                    i.NumeroFactura as NumeroFactura,
		                    i.NumeroGuia as NumeroGuia,
		                    '' as NumeroServicio,
		                    a.Nombre as NombreAlmacen,
		                    p.Descripcion as NombreProyecto,
		                    lo.Descripcion as NombreLote,
		                    lu.Descripcion as NombreLugar,
		                    i.Ubicacion as Ubicacion,
		                    ce.Descripcion as NombreCondicionEquipo,
		                    di.ObservacionesMantenimiento as ObservacionesMantenimiento,
		                    di.Partes as Partes,
		                    di.Consumibles as Consumibles
                    from Ingreso i 
	                    inner join TipoMovimiento t on i.TipoMovimiento_id = t.id
	                    inner join DetalleIngreso di on i.id = di.Ingreso_id
                        inner join Articulo ar on di.Articulo_id = ar.Id
	                    inner join CondicionEquipo ce on di.CondicionEquipo_id = ce.Id
	                    left join Almacen a on i.Almacen_id = a.Id
	                    left join Proyecto p on i.Proyecto_id = p.Id
	                    left join Lote lo on i.Lote_id = lo.Id
	                    left join Lugar lu on i.Lugar_id = lu.Id
                    where	t.Mantenimiento = 1
                            and ar.Id = ? "+
                    (!DateTime.MinValue.Equals(fechaInicio)?"and i.Fecha <= ? and i.Fecha >= ? ":string.Empty)+
                    @"union
                    select	s.Fecha as Fecha,
		                    '' as NumeroFactura,
		                    s.NumeroGuia as NumeroGuia,
		                    s.OrdenServicio as NumeroServicio,
		                    a.Nombre as NombreAlmacen,
		                    p.Descripcion as NombreProyecto,
		                    lo.Descripcion as NombreLote,
		                    lu.Descripcion as NombreLugar,
		                    s.Ubicacion as Ubicacion,
		                    ce.Descripcion as NombreCondicionEquipo,
		                    di.ObservacionesMantenimiento as ObservacionesMantenimiento,
		                    di.Partes as Partes,
		                    di.Consumibles as Consumibles
                    from Salida s
	                    inner join TipoMovimiento t on s.TipoMovimiento_id = t.id
	                    inner join DetalleIngreso di on s.id = di.Ingreso_id
                        inner join Articulo ar on di.Articulo_id = ar.Id
	                    inner join CondicionEquipo ce on di.CondicionEquipo_id = ce.Id
	                    left join Almacen a on s.Almacen_id = a.Id
	                    left join Proyecto p on s.Proyecto_id = p.Id
	                    left join Lote lo on s.Lote_id = lo.Id
	                    left join Lugar lu on s.Lugar_id = lu.Id
                    where	t.Mantenimiento = 1
                            and ar.Id = ? "+
                    (!DateTime.MinValue.Equals(fechaInicio)?"and s.Fecha <= ? and s.Fecha >= ?":string.Empty));
                    var indice = 0;
                    query.SetInt32(indice++, articulo.Id);
                    if (!DateTime.MinValue.Equals(fechaInicio))
                    {
                        query.SetDateTime(indice++, fechaFin);
                        query.SetDateTime(indice++, fechaInicio);
                    }
                    query.SetInt32(indice++, articulo.Id);
                    if (!DateTime.MinValue.Equals(fechaInicio))
                    {
                        query.SetDateTime(indice++, fechaFin);
                        query.SetDateTime(indice, fechaInicio);
                    }
                    query.SetResultTransformer(Transformers.AliasToBean(typeof(ConsultaMantenimientoDTO)));
                    var listaTemporal = query.List<ConsultaMantenimientoDTO>();
                    lista = new List<ConsultaMantenimientoDTO>(listaTemporal.OrderByDescending(x => x.Fecha));
                    transaction.Commit();
                }
            }
            return lista;
        }

        public IList<ConsultaMovimientoDTO> ObtenerMovimientosArticulos(ConsultaMovimientoReq filtro)
        {
            IList<ConsultaMovimientoDTO> lista;
            using (var session = CreateSessionFactory().OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    var query = session.CreateSQLQuery(
                    @"select	i.Fecha as Fecha,
		                    f.Descripcion as NombreFamilia,
		                    sf.Descripcion as NombreSubFamilia,
		                    ar.Codigo as Codigo,
		                    ar.Descripcion as Descripcion,
		                    m.Descripcion as NombreMarca,
		                    ar.Modelo as Modelo,
		                    ar.Serie as Serie,
		                    di.Cantidad as Cantidad,
		                    t.Descripcion as NombreTipoMovimiento,
		                    t.TipoEntradaOSalida as TipoEntradaOSalida,
		                    a.Nombre as NombreAlmacen,
		                    p.Descripcion as NombreProyecto,
		                    lo.Descripcion as NombreLocal,
		                    lu.Descripcion as NombreLugar,
		                    i.Ubicacion as Ubicacion,
		                    ce.Descripcion as NombreCondicionEquipo
                    from Ingreso i 
	                    inner join TipoMovimiento t on i.TipoMovimiento_id = t.id
	                    inner join DetalleIngreso di on i.id = di.Ingreso_id
	                    inner join Articulo ar on di.Articulo_id = ar.Id
	                    inner join Marca m on ar.Marca_id = m.Id
	                    inner join SubFamilia sf on ar.SubFamilia_id = sf.Id
	                    inner join Familia f on sf.Familia_id = f.Id
	                    inner join CondicionEquipo ce on di.CondicionEquipo_id = ce.Id
	                    left join Almacen a on i.Almacen_id = a.Id
	                    left join Proyecto p on i.Proyecto_id = p.Id
	                    left join Lote lo on i.Lote_id = lo.Id
	                    left join Lugar lu on i.Lugar_id = lu.Id "+
                    ArmarFiltroIngreso(filtro) +
                    @"union
                    select	s.Fecha as Fecha,
		                    f.Descripcion as NombreFamilia,
		                    sf.Descripcion as NombreSubFamilia,
		                    ar.Codigo as Codigo,
		                    ar.Descripcion as Descripcion,
		                    m.Descripcion as NombreMarca,
		                    ar.Modelo as Modelo,
		                    ar.Serie as Serie,
		                    di.Cantidad as Cantidad,
		                    t.Descripcion as NombreTipoMovimiento,
		                    t.TipoEntradaOSalida as TipoEntradaOSalida,
		                    a.Nombre as NombreAlmacen,
		                    p.Descripcion as NombreProyecto,
		                    lo.Descripcion as NombreLocal,
		                    lu.Descripcion as NombreLugar,
		                    s.Ubicacion as Ubicacion,
		                    ce.Descripcion as NombreCondicionEquipo
                    from Salida s 
	                    inner join TipoMovimiento t on s.TipoMovimiento_id = t.id
	                    inner join DetalleIngreso di on s.id = di.Ingreso_id
	                    inner join Articulo ar on di.Articulo_id = ar.Id
	                    inner join Marca m on ar.Marca_id = m.Id
	                    inner join SubFamilia sf on ar.SubFamilia_id = sf.Id
	                    inner join Familia f on sf.Familia_id = f.Id
	                    inner join CondicionEquipo ce on di.CondicionEquipo_id = ce.Id
	                    left join Almacen a on s.Almacen_id = a.Id
	                    left join Proyecto p on s.Proyecto_id = p.Id
	                    left join Lote lo on s.Lote_id = lo.Id
	                    left join Lugar lu on s.Lugar_id = lu.Id "+
                    ArmarFiltroSalida(filtro));
                    var indice = AgregarParametros(0,filtro,query);
                    AgregarParametros(indice, filtro, query);
                    query.SetResultTransformer(Transformers.AliasToBean(typeof(ConsultaMovimientoDTO)));
                    lista = query.List<ConsultaMovimientoDTO>();
                    lista = new List<ConsultaMovimientoDTO>(lista.OrderByDescending(x => x.Fecha));
                    transaction.Commit();
                }
            }
            return lista;
        }

        private int AgregarParametros(int indice, ConsultaMovimientoReq filtro, ISQLQuery query)
        {
            query.SetInt32(indice++, filtro.Familia.Id);
            query.SetInt32(indice++, filtro.Familia.Id);
            query.SetInt32(indice++, filtro.SubFamilia.Id);
            query.SetInt32(indice++, filtro.SubFamilia.Id);
            query.SetInt32(indice++, filtro.Marca.Id);
            query.SetInt32(indice++, filtro.Marca.Id);
            query.SetInt32(indice++, filtro.TipoMovimiento.Id);
            query.SetInt32(indice++, filtro.TipoMovimiento.Id);
            query.SetInt32(indice++, filtro.Almacen.Id);
            query.SetInt32(indice++, filtro.Almacen.Id);
            query.SetInt32(indice++, filtro.Proyecto.Id);
            query.SetInt32(indice++, filtro.Proyecto.Id);
            query.SetInt32(indice++, filtro.Lote.Id);
            query.SetInt32(indice++, filtro.Lote.Id);
            query.SetInt32(indice++, filtro.Lugar.Id);
            query.SetInt32(indice++, filtro.Lugar.Id);
            if (!DateTime.MinValue.Equals(filtro.FechaInicio))
            {
                query.SetDateTime(indice++, filtro.FechaFin);
                query.SetDateTime(indice++, filtro.FechaInicio);
            }
            if (!string.IsNullOrEmpty(filtro.CodigoArticulo))
            {
                query.SetString(indice++, filtro.CodigoArticulo + "%");
            }
            return indice;
        }

        private string ArmarFiltroSalida(ConsultaMovimientoReq filtro)
        {
            var buffer = new StringBuilder();
            buffer.Append(@"where	1=1 ");
            buffer.Append("and (? = 0 or f.Id = ?) ");
            buffer.Append("and (? = 0 or sf.Id = ?) ");
            buffer.Append("and (? = 0 or m.Id = ?) ");
            buffer.Append("and (? = 0 or t.Id = ?) ");
            buffer.Append("and (? = 0 or a.Id = ?) ");
            buffer.Append("and (? = 0 or p.Id = ?) ");
            buffer.Append("and (? = 0 or lo.Id = ?) ");
            buffer.Append("and (? = 0 or lu.Id = ?) ");
            if (!DateTime.MinValue.Equals(filtro.FechaInicio))
            {
                buffer.Append("and s.Fecha <= ? and s.Fecha >= ? ");
            }
            if (!string.IsNullOrEmpty(filtro.CodigoArticulo))
            {
                buffer.Append("and ar.Codigo like ? ");
            }
            return buffer.ToString();
        }

        private string ArmarFiltroIngreso(ConsultaMovimientoReq filtro)
        {
            var buffer = new StringBuilder();
            buffer.Append(@"where	1=1 ");
            buffer.Append("and (? = 0 or f.Id = ?) ");
            buffer.Append("and (? = 0 or sf.Id = ?) ");
            buffer.Append("and (? = 0 or m.Id = ?) ");
            buffer.Append("and (? = 0 or t.Id = ?) ");
            buffer.Append("and (? = 0 or a.Id = ?) ");
            buffer.Append("and (? = 0 or p.Id = ?) ");
            buffer.Append("and (? = 0 or lo.Id = ?) ");
            buffer.Append("and (? = 0 or lu.Id = ?) ");
            if (!DateTime.MinValue.Equals(filtro.FechaInicio))
            {
                buffer.Append("and i.Fecha <= ? and i.Fecha >= ? ");
            }
            if (!string.IsNullOrEmpty(filtro.CodigoArticulo))
            {
                buffer.Append("and ar.Codigo like ? ");
            }
            return buffer.ToString();                
        }
    }
}